"""
类与对象
    1、类的定义：
        class 类名:
            类的属性      // 类的属性称为 成员变量
            类的行为       // 类的行为称为 成员方法
            def 方法名(self)：    //在定义类的方法时，self是比传，它代表的是这个类对象本身（跟this一样）
            # 私有成员使用两个下划线定义，类对象无法直接访问，只能在类内部进行访问
            __私有属性
            def __私有方法()
    2、创建类的对象：
        变量名 = 类名()
    3、注意：方法是定义在类里面的，而函数是定义在类外面的
    4、定义成员方法是必须要传self
    5、成员方法在调用成员属性时，必须使用 self.类的属性名 调用
    6、构造函数定义：
        def __init__(self):
    7、构造函数在构建类对象时会自动执行
    8、创建类型对象时可以传参，参数会传递给构造函数，可以给成员变量赋值，同时也可以定义成员变量
    9、常见内置方法（魔术方法）：
        1） def __init__(self)     # 构造方法
        2） def __str__(self)      # 将类对象转换字符串
        3） def __lt__(self)       # 用于2个类对象之间进行小于/大于比较（实际是小于）
        4） def __le__(self)       # 用于2个类对象之间进行小于等于/大于等于比较
        5） def __eq__(self)       # 用于2个类对象之间进行相等比较
类的封装：
    1、定义：将现实世界事物在类中描述为属性和方法，即为封装
    2、私有成员：不对外公开使用的，外部不能通过类对象直接进行访问，类内部其他成员可以访问私有成员
    3、如何定义私有成员：私有成员变量和方法均使用__开头进行定义
类的继承：
    1、定义：一个类可以继承另一个类的成员变量和成员方法
    2、单继承语法：
        class 类1(类2):
            xxx
    3、多继承语法：逗号隔开
        class 类1(类2, 类3,.....)
            xxxx
    4、注意：如果继承的多个父类中有相同的变量和方法时，最先继承的优先级高，
    5、pass的作用：占位符语句，用来保证函数方法或类定义的完整性，表示无内容，空的意思
        class xx:
            pass
    6、复写父类的成员变量和成员函数：
        1、在子类里面可以重新定义父类中的成员变量和成员方法，成为子类的变量及方法
        2、复写父类的成员变量和方法后，可以通过以下两种方式重新访问父类的成员变量及方法：
            1）使用父类名进行访问
                父类名.成员变量
                父类名.成员方法(self)
            2）使用super()访问父类的成员变量和成员方法
                super().成员变量
                super().成员方法
        3、注意：父类的成员变量和成员方法被复写后，子类只能在内部访问父类的变量和函数，子类的实体类对象默认调用子类复写的变量和方法
注释： （只做提示）
    1、变量类型注释：
        1）基础数据类型注释：
            变量名: 数据类型 = 赋值
            name: str = "maomao"   # 基础数据的类型注释
        2）基础容量类型注释：
            my_str: str = ”holle“   # 字符串
            my_list: list = [1,2]   # 数组
            my_tuple: tuple = (1,2)   # 元组
            my_set: set = {1,2}   # 集合
            my_dict: dict = {"name": "maomao"}   # 字典
        3）容量类型详细注释：
            my_list: list[int] = [1,2]   # 数组
            my_tuple: tuple[int,str,bool] = (1,"Hello",True)   # 元组
            my_set: set[int] = {1,2}   # 集合
            my_dict: dict[str,str] = {"name": "maomao"}   # 字典
        4）类对象类型注释：
            class Student:
                pass
            stu: Student = Student()   # 类对象的类型注释
        5）使用# type：进行注释
            name = '猫猫'                  # type:str
            person = {"name":"maomao"}    # type:dict
            student = Student()           # type:Student
        6）函数形参的类型注释：
            def fun(参数1:数据类型,参数2:int,参数3:str):
                pass
        7）函数返回值的类型注释：
            def fun() ->数据类型:
                pass
        8）类和类型注释Union
            # 当变量/容器/形参/返回值里面有多个类型时，可以使用Union进行注释，表示这里面可以是 类型1 | 类型2
            from typing import Union    # 需导入Union包
            my_list : list[Union[int,str]]= [1,"猫",2,"菜"]    # list 里面有 int也有str类型，使用Union注释list里面既有int也有str
            def fun(my_list: list[Union[int,str]]) ->Union[int,str]
多态：
    1、多态是指，同一个行为，使用不同的对象获得不同的状态
    2、抽象类（读取数据）：包含抽象方法的类
    3、抽象方法：没有具体实现的方法（使用pass）
    4、抽象类的作用：
        1）用于顶层设计（设计标准），以便子类做具体实现
        2）对子类的一种软性约束，要求子类必须要复写父类的方法，并配合多态使用
 """
class Student:
    # name = None    # 定义成员变量，需赋值
    # age = None
    # sex = None

    # 构造方法
    def __init__(self,name,age,sex):    # 构造方法，创建类对象时自动执行，在创建类对象时传的参数可以自行传入构造函数中
        self.name = name     # 构造方法内可以定义成员变量
        self.age = age
        self.sex = sex

    # 魔术方法
    def __str__(self):     # 将类对象转换成字符串输出
        return f"类对象是,name:{self.name},age:{self.age},sex:{self.sex}"

    def __lt__(self, other):    # 使用小于号进行比较
        return self.age < other.age

    def __le__(self,other):    # 使用小于等于号进行比较
        return self.age <= other.age

    def __eq__(self,other):    # 使用等号进行比较
        return self.age == other.age

    def name_print(self):     # 定义成员方法
        print(self.name)      # 成员方法内使用 self.变量名 访问成员变量


# stu1 = Student("猫猫",18,"女")
# stu2 = Student("菜菜",20,"女")
# print(stu1)    # 直接输出类对象的话是一个内存地址
# print(str(stu1))
# print(stu1 < stu2)   # 比较大小
#
# stu1 = Student("猫猫",20,"女")
# stu2 = Student("菜菜",20,"女")
# print(stu1 <= stu2)   # 比较大小
#
# stu1 = Student("猫猫",20,"女")
# stu2 = Student("菜菜",20,"女")
# print(stu1 == stu2)   # 比较大小

# ------------私有属性和方法
class Phone_5g:
    __is_5g_enable = False      # 私有属性

    def __check_5g(self):     # 私有方法
        if self.__is_5g_enable:
            print("5g开启")
        else:
            print("5g关闭，使用4g网络")

    def call_by_5g(self):     # 成员方法
        self.__check_5g()
        print("正在通话中...")

phone = Phone_5g()
phone.call_by_5g()

# ----------继承
class Phone_info:
    IMEI = 00000    # 序列号
    producer = "猫猫家"    # 厂商

    def info_print(self):
        print(f"手机序列号：{self.IMEI},厂商：{self.producer}")

class My_phone1(Phone_5g):    # 单继承
    pass  # pass语句，当类里面无内容时可以适用pass语句来使代码的完整性

phone1 = My_phone1()
phone1.call_by_5g()      # 继承父类的成员方法和属性


class My_phone2(Phone_5g,Phone_info):    # 多继承
    IMEI = 123456  # 序列号      # 复写父类的成员变量
    producer = "华为"  # 厂商

    def info_print(self):     # 复写父类的成员方法
        print(f"我手机序列号：{self.IMEI},厂商：{self.producer}，买买买")
        # 使用super().调用被复写的父类的属性/方法
        print(f"父类手机序列号是:{super().IMEI},父类厂商是：{super().producer}")
        # 使用父类.调用被复写的父类的属性/方法
        print(f"父类手机序列号是:{Phone_info.IMEI},父类厂商是：{Phone_info.producer}")

phone2 = My_phone2()
phone2.info_print()


# ---------------类型注解
# 变量注释
is_girl: bool = True
name: str = "猫猫"
age: int = 18
my_list: list = [1,2,3]
my_tuple: tuple = (1,2,3)
my_set: set = {1,2,3}
my_dict: dict = {'name':'maomao','age':18}

# 详细变量注释
my_list: list[int] = [1,2,3]
my_tuple: tuple[int,int,str] = (1,2,"maomao")
my_set: set[int,bool] = {1,True}
my_dict: dict[str,str] = {'name':'maomao','age':18}

# 函数中的形参注释
def add_fun(x: int,y: int):
    return x+y

# 函数中的返回值注释
def info() -> str:
    in_fo = '你好你好！'
    return in_fo

# Union注释需引入tying模块
from typing import Union

# 变量的Union注释
my_list: list[Union[int,str]] = [1,2,'maomao',2,'maomao']
# 函数的Union注释
def fun_list(my_list1: list[Union[int,str]]) -> Union[int,str]:
    return my_list1